﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Threading;
using io = System.IO;
using wf = System.Windows.Forms;
using dw = System.Drawing;

namespace editor.app
{
    /// <summary>
    /// MapWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MapWindow : Window
    {
        const string EXT_NAME = comm.objst.DMap.Data.FILE_EXT_NAME;

        public double Scale
        {
            get
            {
                if (gridLayerRoot.RenderTransform is ScaleTransform)
                {
                    var st = (ScaleTransform)gridLayerRoot.RenderTransform;
                    return st.ScaleX;
                }
                return 1;
            }
            set
            {
                value = Math.Max(.1, value);
                gridLayerRoot.RenderTransform = new ScaleTransform
                {
                    ScaleX = value,
                    ScaleY = value
                };
                _map.DesignScale = value;
            }
        }

        comm.objst.DMap.Data _map = null;
        string _fileName = "";
        string _sign = "";
        Dictionary<string, CheckBox> _layerCkDic = new Dictionary<string, CheckBox>();
        Dictionary<string, Canvas> _layerDic = new Dictionary<string, Canvas>();
        Dictionary<string, comm.objst.DMap.Data.Obj> _externalObjDic = null;
        bool hasExternalDic = false;
        List<int[]> _pathList = null;

        public Action<Dictionary<string, comm.objst.DMap.Data.Obj>> OnSaveCallback = null;

        public MapWindow(string fileName = null, Dictionary<string, comm.objst.DMap.Data.Obj> externalObjDic = null, List<int[]> pathList = null)
        {
            InitializeComponent();
            this.LoadConfig1();
            _externalObjDic = externalObjDic;
            hasExternalDic = _externalObjDic != null;
            _pathList = pathList;

            WindowState = WindowState.Maximized;

            if (fileName != null)
            {
                _fileName = fileName;
                OpenFile();
            }

            #region contextMenu
            var contextMenu = new ContextMenu { FontSize = 14 };
            TextOptions.SetTextFormattingMode(contextMenu, TextFormattingMode.Display);

            var mClear = new MenuItem { Header = new TextBlock { Text = "清空" } };
            mClear.Click += new RoutedEventHandler(mClear_Click);
            contextMenu.Items.Add(mClear);

            var mExternalClear = new MenuItem { Header = new TextBlock { Text = "清空Ex对象" } };
            mExternalClear.Click += new RoutedEventHandler(mExternalClear_Click);
            contextMenu.Items.Add(mExternalClear);

            svLayer.ContextMenu = contextMenu;
            #endregion

            btnNew.Click += new RoutedEventHandler(btnNew_Click);
            KeyDown += new KeyEventHandler(MapWindow_KeyDown);
            btnReload.Click += new RoutedEventHandler(btnReload_Click);
            btnSetSize.Click += new RoutedEventHandler(btnSetSize_Click);
            tbSize.KeyDown += new KeyEventHandler((o, e) =>
            {
                if (e.Key == Key.Enter)
                {
                    btnSetSize_Click(btnSetSize, new RoutedEventArgs());
                }
            });
            btnEditObjs.Click += new RoutedEventHandler(btnEditObjs_Click);
            btnSetPathFromPNG.Click += new RoutedEventHandler(btnSetPathFromPNG_Click);
            btnClearLog.Click += new RoutedEventHandler(btnClearLog_Click);
            btnSetBackground.Click += new RoutedEventHandler(btnSetBackground_Click);

            gridLayerRoot.Drag(LayerDrag);
            FillRes();

            #region loop
            comm.ThreadHelper.Run(() =>
            {
                while (true)
                {
                    if (_map != null)
                    {
                        var isChange = CheckSignChange();
                        Dispatcher.Invoke(new Action(() =>
                        {
                            Title = io.Path.GetFileName(_fileName) + (isChange ? "*" : "") + " " +
                                _map.Width + "x" + _map.Height + " " +
                                (_map.Width * _map.PathSize) + "x" + (_map.Height * _map.PathSize);
                            UpdateLayers();
                        }));
                    }
                    Thread.Sleep(100);
                }
            });
            #endregion
        }

        void mExternalClear_Click(object sender, RoutedEventArgs e)
        {
            var elis = new List<string>();
            foreach (var key in _map.ObjDic.Keys)
            {
                if (_map.ObjDic[key].IsExternal)
                {
                    elis.Add(key);
                }
            }
            foreach (var key in elis)
            {
                _map.ObjDic.Remove(key);
            }
            Fill();
        }
        void btnSetBackground_Click(object sender, RoutedEventArgs e)
        {
            var ofd = new wf.OpenFileDialog();
            if (ofd.ShowDialog().ToString() == "OK")
            {
                #region read bitmap
                try
                {
                    using (var bitmap = new dw.Bitmap(ofd.FileName))
                    {
                        var size = comm.objst.DMap.Data.IMAGE_BLOCK_SIZE;
                        var wc = Math.Ceiling(bitmap.Width / (double)size);
                        var hc = Math.Ceiling(bitmap.Height / (double)size);
                        _map.BGImageBlockList.Clear();

                        for (int x = 0; x < wc; x++)
                        {
                            for (int y = 0; y < hc; y++)
                            {
                                using (var blockBitmap = new dw.Bitmap(size, size))
                                {
                                    var g = dw.Graphics.FromImage(blockBitmap);
                                    g.DrawImage(bitmap,
                                        new dw.Rectangle(0, 0, size, size),
                                        new dw.Rectangle(x * size, y * size, size, size),
                                        dw.GraphicsUnit.Pixel);
                                    using (var ms = new io.MemoryStream())
                                    {
                                        blockBitmap.Save(ms, dw.Imaging.ImageFormat.Png);

                                        _map.BGImageBlockList.Add(new comm.objst.DMap.Data.ImageBlock
                                        {
                                            X = x * size,
                                            Y = y * size,
                                            ImageBytes = ms.ToArray()
                                        });

                                    }
                                    g.Dispose();
                                }
                            }
                        }

                    }
                    Fill();
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
                #endregion
            }
        }
        void btnClearLog_Click(object sender, RoutedEventArgs e)
        {
            spLog.Children.Clear();
        }
        void btnEditObjs_Click(object sender, RoutedEventArgs e)
        {
            var window = new TextWindow { Width = 800, Height = 600 };
            window.InputText = comm.JsonSerializer.Serialize(_map.ObjDic, false, true);
            window.ShowDialog();
            try
            {

                var objDic = comm.JsonSerializer.Deserialize<Dictionary<string, comm.objst.DMap.Data.Obj>>(window.InputText);
                if (objDic != null)
                {
                    _map.ObjDic = objDic;
                    Fill();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        void mClear_Click(object sender, RoutedEventArgs e)
        {
            _map.ObjDic.Clear();
            Fill();
        }
        void btnSetPathFromPNG_Click(object sender, RoutedEventArgs e)
        {
            var ofd = new wf.OpenFileDialog
            {
                Filter = "*.png|*.png"
            };
            if (ofd.ShowDialog().ToString() == "OK")
            {
                #region read bitmap
                try
                {
                    using (var bitmap = new dw.Bitmap(ofd.FileName))
                    {
                        var wc = bitmap.Width / _map.PathSize;
                        var hc = bitmap.Height / _map.PathSize;

                        for (int bx = 0; bx < wc; bx++)
                        {
                            for (int by = 0; by < hc; by++)
                            {
                                if (bx < _map.Width && by < _map.Height)
                                {
                                    var count = 0;
                                    for (int x = 0; x < _map.PathSize; x++)
                                    {
                                        for (int y = 0; y < _map.PathSize; y++)
                                        {
                                            if (bitmap.GetPixel((int)(x + bx * _map.PathSize), (int)(y + by * _map.PathSize)).A == 0)
                                            {
                                                count++;
                                            }
                                        }
                                    }
                                    _map.Paths[bx, by] = count > _map.PathSize * _map.PathSize / 2 ? comm.objst.PathType.EMPTY : comm.objst.PathType.FORBID;
                                }
                            }
                        }
                    }
                    Fill();
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
                #endregion
            }
        }
        void btnSetSize_Click(object sender, RoutedEventArgs e)
        {
            var ss = tbSize.Text.Split(',');
            uint w = 0, h = 0;
            if (ss.Length == 2 && uint.TryParse(ss[0].Trim(), out w) && uint.TryParse(ss[1].Trim(), out h))
            {
                SetSize(Math.Max(1, (int)w), Math.Max(1, (int)h));
            }
            Fill();
        }
        void btnReload_Click(object sender, RoutedEventArgs e)
        {
            if (_fileName != null)
            {
                OpenFile();
            }
        }
        void MapWindow_KeyDown(object sender, KeyEventArgs e)
        {
            if (Keyboard.Modifiers == ModifierKeys.Control)
            {
                if (e.Key == Key.S)
                {
                    SaveFile();
                }
                else if (e.Key == Key.OemPlus)
                {
                    Scale += .1;
                }
                else if (e.Key == Key.OemMinus)
                {
                    Scale -= .1;
                }
                else if (e.Key == Key.D0)
                {
                    Scale = 1;
                }
                else if (e.Key == Key.Enter)
                {
                    _map.DesignX = 200;
                    _map.DesignY = 4;
                    Fill();
                }
            }
        }
        void btnNew_Click(object sender, RoutedEventArgs e)
        {
            var sfd = new wf.SaveFileDialog { Filter = EXT_NAME + "|*" + EXT_NAME };
            if (sfd.ShowDialog().ToString() == "OK")
            {
                _map = new comm.objst.DMap.Data();
                SetSize(10, 10);
                _fileName = sfd.FileName;
                SaveFile();
                OpenFile();
            }
        }
        void ckAll_Checked(object sender, RoutedEventArgs e)
        {
            var ck = (CheckBox)sender;
            foreach (var ckk in _layerCkDic.Values)
            {
                ckk.IsChecked = ck.IsChecked;
            }
        }
        void mEditRPack_Click(object sender, RoutedEventArgs e)
        {
            var mi = (MenuItem)sender;
            var file = mi.Tag.ToString();
            var window = new RPackWindow(file);
            window.ShowDialog();
            Fill();
            FillRes();
        }
        void mEditDObjRPack_Click(object sender, RoutedEventArgs e)
        {
            var mi = (MenuItem)sender;
            var dObjectId = mi.Tag.ToString();
            var dobj = App.DefineFile.GetObject(dObjectId);
            if (dobj != null)
            {
                var window = new RPackWindow(dobj.RPackFile);
                window.ShowDialog();
                Fill();
                FillRes();
            }
        }
        void mEditDObj_Click(object sender, RoutedEventArgs e)
        {
            var mi = (MenuItem)sender;
            var dObjectId = mi.Tag.ToString();
            var dobj = App.DefineFile.GetObject(dObjectId);
            if (dobj != null)
            {
                var window = new ObjWindow(dobj.ObjFile);
                window.ShowDialog();
                Fill();
                FillRes();
            }
        }

        void LayerDrag(FrameworkElement sender, MouseEventArgs e, string type, double ox, double oy)
        {
            var pt = e.GetPosition(svLayer);
            double x = pt.X, y = pt.Y;
            x -= ox * Scale;
            y -= oy * Scale;
            gridLayerRoot.Margin = new Thickness(x, y, 0, 0);
            _map.DesignX = (int)x;
            _map.DesignY = (int)y;
        }
        void ResDrag(FrameworkElement sender, MouseEventArgs e, string type, double ox, double oy)
        {
            if (type == "move")
            {
                brDragIcon.Visibility = Visibility.Visible;
                var pt = e.GetPosition(gridRoot);
                brDragIcon.Margin = new Thickness(pt.X - brDragIcon.Width / 2, pt.Y - brDragIcon.Width / 2, 0, 0);
            }
            else if (type == "up")
            {
                brDragIcon.Visibility = Visibility.Collapsed;
                var pt2 = e.GetPosition(gridLayerRoot);
                var pt3 = gridLayerRoot.TranslatePoint(new Point(), svLayer);
                var rt = new Rect(0, 0,
                    _map.Width * _map.PathSize * Scale,
                    _map.Height * _map.PathSize * Scale);
                if (rt.Contains(pt2))
                {
                    AddObj(pt2, ((FrameworkElement)sender.Parent).Tag.ToString());
                }
            }
        }

        void UpdateLayers()
        {
            foreach (var key in _layerCkDic.Keys)
            {
                var ck = _layerCkDic[key];
                var cv = _layerDic[key];
                cv.Visibility = ck.IsChecked == true ? Visibility.Visible : Visibility.Collapsed;
                ck.Visibility = cv.Children.Count > 0 ? Visibility.Visible : Visibility.Collapsed;
                ck.Content = new TextBlock
                {
                    Text = key + "(" + cv.Children.Count + ")",
                    FontSize = 12,
                    Foreground = new SolidColorBrush(Color2.Yellow())
                };
            }
        }
        void AddObj(Point pt, string type)
        {
            int locX = (int)Math.Floor(pt.X / _map.PathSize),
                locY = (int)Math.Floor(pt.Y / _map.PathSize);
            var ss = type.Split(':');
            var key = comm.GUID.NewString();
            if (ss[0] == "sprite")
            {
                #region Add Sprite
                _map.ObjDic.Add(key, new comm.objst.DMap.Data.Sprite
                {
                    IsExternal = hasExternalDic,
                    Name = key,
                    LocX = locX,
                    LocY = locY,
                    RPackFile = ss[1],
                    SpriteKey = ss[2]
                });
                #endregion
            }
            else if (ss[0] == "sobj")
            {
                #region Add SObj
                var obj = new comm.objst.DMap.Data.SObj
                {
                    IsExternal = hasExternalDic,
                    Name = key,
                    LocX = locX,
                    LocY = locY,
                    DObjectId = ss[1]
                };
                server.app.DataManager.VerifyMapObjEV(App.DefineFile, obj);
                _map.ObjDic.Add(key, obj);
                #endregion
            }
            Fill();
        }
        void SetSize(int w, int h)
        {
            var pathData = new comm.objst.PathType[w, h];
            for (int x = 0; x < w; x++)
            {
                for (int y = 0; y < h; y++)
                {
                    var v = comm.objst.PathType.EMPTY;
                    if (x < _map.Width && y < _map.Height)
                    {
                        v = _map.Paths[x, y];
                    }
                    pathData[x, y] = v;
                }
            }
            _map.Paths = pathData;
            _map.Width = w;
            _map.Height = h;
        }
        Canvas GetLayer(string key)
        {
            return _layerDic[key];
        }

        TreeViewItem MakeTVI(string txt, Color txtColor, object tag = null, string icon = null, bool drag = false)
        {
            var sp = new StackPanel { Background = new SolidColorBrush(Color2.Transparent()), Orientation = Orientation.Horizontal };
            var bitmapImage = new BitmapImage();
            if (icon != null)
            {
                bitmapImage.FromFile(icon);
            }
            sp.Children.Add(new Image { Source = bitmapImage, Width = 16, Height = 16, Margin = new Thickness(0, 0, 4, 0) });
            sp.Children.Add(new TextBlock { Text = txt, Foreground = new SolidColorBrush(txtColor) });
            if (drag)
            {
                sp.Drag(ResDrag);
            }
            return new TreeViewItem { Header = sp, Tag = tag, IsExpanded = true };
        }
        void FillDir(TreeViewItem tvi, string dir, string rdir)
        {
            var dirs = io.Directory.GetDirectories(dir);
            var files = io.Directory.GetFiles(dir, "*" + comm.objst.RPack.FILE_EXT_NAME);

            var cdir = io.Path.GetFileName(dir);
            var tviFolder = MakeTVI(cdir, Color2.Black(90), null, "icon/folder.png");
            if (cdir == ".svn")
            {
                return;
            }
            rdir += rdir == null ? "[ROOT]/" : cdir + "/";
            foreach (var d in dirs)
            {
                FillDir(tviFolder, d, rdir);
            }
            foreach (var file in files)
            {
                var cfile = io.Path.GetFileName(file);
                var tviRPack = MakeTVI(cfile, Color2.Black(), null, "icon/rpack.png");

                var contextMenu = new ContextMenu { FontSize = 14 };
                TextOptions.SetTextFormattingMode(contextMenu, TextFormattingMode.Display);
                var mEditRPack = new MenuItem { Tag = file, Header = new TextBlock { Text = "Edit" } };
                mEditRPack.Click += new RoutedEventHandler(mEditRPack_Click);
                contextMenu.Items.Add(mEditRPack);
                tviRPack.ContextMenu = contextMenu;

                try
                {
                    var rpack = comm.BinarySerializer.Deserialize<comm.objst.RPack>(io.File.ReadAllBytes(file));
                    var keys = rpack.GetAllResourceKeys(typeof(comm.objst.RSprite));
                    foreach (var spriteKey in keys)
                    {
                        var sprite = rpack.GetResource<comm.objst.RSprite>(spriteKey);
                        var tviSprite = MakeTVI(sprite.Name, Color2.Black(), "sprite:" + rdir + cfile + ":" + spriteKey, "icon/sprite.png", true);
                        tviRPack.Items.Add(tviSprite);
                    }
                }
                catch (Exception)
                {
                    tviRPack.Items.Add(new TreeViewItem
                    {
                        Header = new TextBlock
                        {
                            Text = "load err!",
                            Foreground = new SolidColorBrush(Color2.Red())
                        }
                    });
                }
                tviFolder.Items.Add(tviRPack);
            }
            tvi.Items.Add(tviFolder);
        }
        void FillRes()
        {
            treeRes.Items.Clear();

            var tviRPack = new TreeViewItem { Header = "RPacks", IsExpanded = true };
            FillDir(tviRPack, App.Config.BinDataFolder, null);
            treeRes.Items.Add(tviRPack);

            var tviObjs = new TreeViewItem { Header = "Objs", IsExpanded = true };
            var objTypes = comm.objst.DObject.Data.GetObjTypes();
            var objs = App.DefineFile.GetAllObject();
            var dic = new Dictionary<string, TreeViewItem>();
            foreach (var objType in objTypes)
            {
                var tvi = new TreeViewItem
                {
                    Header = new TextBlock
                    {
                        Foreground = new SolidColorBrush(Color2.Black(80)),
                        Text = objType
                    },
                    IsExpanded = true
                };
                tviObjs.Items.Add(tvi);
                dic.Add(objType, tvi);
            }
            foreach (var dObjectId in objs)
            {
                var obj = App.DefineFile.GetObject(dObjectId);
                var tviObj = MakeTVI(dObjectId, Color2.Black(), "sobj:" + dObjectId, "icon/obj.png", true);

                var contextMenu = new ContextMenu { FontSize = 14 };
                TextOptions.SetTextFormattingMode(contextMenu, TextFormattingMode.Display);

                var mEditDObj = new MenuItem { Tag = dObjectId, Header = new TextBlock { Text = "Edit DObj" } };
                mEditDObj.Click += new RoutedEventHandler(mEditDObj_Click);
                contextMenu.Items.Add(mEditDObj);

                var mEditDObjRPack = new MenuItem { Tag = dObjectId, Header = new TextBlock { Text = "Edit RPack" } };
                mEditDObjRPack.Click += new RoutedEventHandler(mEditDObjRPack_Click);
                contextMenu.Items.Add(mEditDObjRPack);

                tviObj.ContextMenu = contextMenu;

                dic[obj.ObjType.ToString()].Items.Add(tviObj);
            }
            treeRes.Items.Add(tviObjs);
        }

        void Fill()
        {
            tbSize.Text = _map.Width + "," + _map.Height;
            tbPathSize.Text = _map.PathSize.ToString();
            btnSetBackground.Content = "设置背景(" + _map.BGImageBlockList.Count + ")";

            int w = _map.PathSize * _map.Width,
                h = _map.PathSize * _map.Height;

            gridLayerRoot.Width = w;
            gridLayerRoot.Height = h;

            gridLayerRoot.Margin = new Thickness(_map.DesignX, _map.DesignY, 0, 0);
            Scale = _map.DesignScale;

            _layerDic.Clear();
            _layerCkDic.Clear();
            spLayers.Children.Clear();
            gridLayers.Children.Clear();
            var layers = comm.objst.DMap.Data.GetMapDesignLayerTypes();

            #region layers
            var ckAll = new CheckBox
            {
                Content = new TextBlock
                {
                    Text = "ALL",
                    FontSize = 12,
                    Foreground = new SolidColorBrush(Color2.Yellow())
                },
                IsChecked = true,
                Focusable = false
            };
            ckAll.Checked += new RoutedEventHandler(ckAll_Checked);
            ckAll.Unchecked += new RoutedEventHandler(ckAll_Checked);
            spLayers.Children.Add(ckAll);
            foreach (var layer in layers)
            {
                var cv = new Canvas { Width = w, Height = h };
                gridLayers.Children.Add(cv);
                _layerDic.Add(layer, cv);

                var ck = new CheckBox
                {
                    IsChecked = true,
                    Focusable = false,
                    Visibility = Visibility.Collapsed
                };
                spLayers.Children.Add(ck);
                _layerCkDic.Add(layer, ck);
            }
            #endregion

            #region background
            var cvBG = GetLayer(comm.objst.MapLayerType.BACKGROUND.ToString());
            foreach (var item in _map.BGImageBlockList)
            {
                if (item.ImageBytes != null)
                {
                    var bitmap = new BitmapImage();
                    bitmap.FromBytes(item.ImageBytes);
                    var br = new Border
                    {
                        BorderBrush = new SolidColorBrush(Color2.Green()),
                        BorderThickness = new Thickness(1),
                        Child = new Image { Source = bitmap, Width = bitmap.PixelWidth, Height = bitmap.PixelHeight }
                    };
                    br.SetLeftTop(item.X, item.Y);
                    cvBG.Children.Add(br);
                }
            }
            #endregion

            #region grid
            var cvGrid = GetLayer(comm.objst.MapLayerType.GRID.ToString());

            int dotSize = 20;
            var br1 = new Ellipse { Width = dotSize, Height = dotSize, Fill = new SolidColorBrush(Color2.White(50)) };
            br1.SetLeftTop(-dotSize / 2, -dotSize / 2);
            var br2 = new Ellipse { Width = dotSize, Height = dotSize, Fill = new SolidColorBrush(Color2.White(50)) };
            br2.SetLeftTop(w - dotSize / 2, -dotSize / 2);
            var br3 = new Ellipse { Width = dotSize, Height = dotSize, Fill = new SolidColorBrush(Color2.White(50)) };
            br3.SetLeftTop(-dotSize / 2, h - dotSize / 2);
            var br4 = new Ellipse { Width = dotSize, Height = dotSize, Fill = new SolidColorBrush(Color2.White(50)) };
            br4.SetLeftTop(w - dotSize / 2, h - dotSize / 2);
            cvGrid.Children.Add(br1);
            cvGrid.Children.Add(br2);
            cvGrid.Children.Add(br3);
            cvGrid.Children.Add(br4);

            for (int x = 1; x < _map.Width; x++)
            {
                var rect = new Rectangle { Width = 1, Height = h, Fill = new SolidColorBrush(Color2.White(10)) };
                rect.SetLeft(x * _map.PathSize);
                cvGrid.Children.Add(rect);
            }
            for (int y = 1; y < _map.Height; y++)
            {
                var rect = new Rectangle { Width = w, Height = 1, Fill = new SolidColorBrush(Color2.White(10)) };
                rect.SetTop(y * _map.PathSize);
                cvGrid.Children.Add(rect);
            }
            #endregion

            if (_pathList != null)
            {
                var path = StarWindow.Block.MakePath(_pathList);
                path.Width = w;
                path.Height = h;
                path.Stretch = Stretch.Fill;
                path.Stroke = new SolidColorBrush(Color2.Orange(50));
                path.StrokeThickness = 2;
                cvGrid.Children.Add(path);
            }

            #region path
            var cvPath = GetLayer(comm.objst.MapLayerType.PATH.ToString());
            var image = new Image { Width = w, Height = h };
            var bitmapImage = new BitmapImage();
            using (var bitmap = new dw.Bitmap(w, h))
            {
                var g = dw.Graphics.FromImage(bitmap);
                g.SmoothingMode = dw.Drawing2D.SmoothingMode.AntiAlias;
                for (int x = 0; x < _map.Width; x++)
                {
                    for (int y = 0; y < _map.Height; y++)
                    {
                        if (_map.Paths[x, y] == comm.objst.PathType.FORBID)
                        {
                            g.DrawRectangle(new dw.Pen(dw.Color.FromArgb(255 / 100 * 50, dw.Color.Yellow), 2),
                                new dw.Rectangle(x * _map.PathSize, y * _map.PathSize, _map.PathSize, _map.PathSize));
                        }
                    }
                }
                g.Dispose();
                using (var ms = new io.MemoryStream())
                {
                    bitmap.Save(ms, dw.Imaging.ImageFormat.Png);
                    bitmapImage.FromBytes(ms.ToArray());
                }
            }
            image.Source = bitmapImage;
            cvPath.Children.Add(image);
            #endregion

            FillObjs();
        }
        void FillObjs()
        {
            foreach (var moKey in _map.ObjDic.Keys)
            {
                var mobj = _map.ObjDic[moKey];
                if (mobj is comm.objst.DMap.Data.Sprite)
                {
                    #region Map Sprite
                    var sprite = (comm.objst.DMap.Data.Sprite)mobj;
                    var file = sprite.RPackFile.Replace("[ROOT]", App.Config.BinDataFolder);
                    try
                    {
                        var rpack = comm.BinarySerializer.Deserialize<comm.objst.RPack>(io.File.ReadAllBytes(file));
                        var spriteView = new SpriteView(_layerDic, rpack, sprite.SpriteKey, false, moKey, mobj, sprite.SpriteGroupKey);
                        spriteView.CmdCallback = CmdCallback;
                        spriteView.SetLoc(sprite.LocX, sprite.LocY);
                    }
                    catch (Exception ex)
                    {
                        Log("load RPack file err! " + ex.Message);
                    }
                    #endregion
                }
                else if (mobj is comm.objst.DMap.Data.SObj)
                {
                    #region Map SObj
                    var mapObj = (comm.objst.DMap.Data.SObj)mobj;
                    server.app.DataManager.VerifyMapObjEV(App.DefineFile, mapObj);
                    var dobj = App.DefineFile.GetObject(mapObj.DObjectId);
                    if (dobj != null)
                    {
                        try
                        {
                            var rpack = comm.BinarySerializer.Deserialize<comm.objst.RPack>(io.File.ReadAllBytes(dobj.RPackFile));
                            var spriteView = new SpriteView(_layerDic, rpack, "FindName:" + mapObj.DObjectId + "_" + mapObj.DesignAction, false, moKey, mobj, mapObj.DesignSpriteGroupKey);
                            spriteView.CmdCallback = CmdCallback;
                            spriteView.SetLoc(mapObj.LocX, mapObj.LocY);
                        }
                        catch (Exception ex)
                        {
                            Log("DObjectId:" + mapObj.DObjectId + " err! load RPack file err! " + ex.Message);
                        }
                    }
                    else
                    {
                        Log("DObjectId:" + mapObj.DObjectId + " not found!");
                    }
                    #endregion
                }
            }
        }

        void CmdCallback(string cmd, params object[] args)
        {
            if (cmd == "fill")
            {
                Fill();
            }
            else if (cmd == "move")
            {
                var key = args[0].ToString();
                int locX = (int)args[1], locY = (int)args[2];
                _map.ObjDic[key].LocX = locX;
                _map.ObjDic[key].LocY = locY;
            }
            else if (cmd == "delete")
            {
                var key = args[0].ToString();
                _map.ObjDic.Remove(key);
                Fill();
            }
            else if (cmd == "editRPack")
            {
                #region Edit RPack
                var key = args[0].ToString();
                var obj = _map.ObjDic[key];
                RPackWindow window = null;
                if (obj is comm.objst.DMap.Data.Sprite)
                {
                    var sprite = (comm.objst.DMap.Data.Sprite)obj;
                    window = new RPackWindow(sprite.RPackFile.Replace("[ROOT]", App.Config.BinDataFolder), sprite.SpriteKey);
                }
                else if (obj is comm.objst.DMap.Data.SObj)
                {
                    var sobj = (comm.objst.DMap.Data.SObj)obj;
                    var dobj = App.DefineFile.GetObject(sobj.DObjectId);
                    if (dobj != null)
                    {
                        window = new RPackWindow(dobj.RPackFile);
                    }
                }
                if (window != null)
                {
                    window.ShowDialog();
                    Fill();
                }
                #endregion
            }
            else if (cmd == "editDObj")
            {
                #region Edit DObj
                var key = args[0].ToString();
                var obj = _map.ObjDic[key];
                var sobj = (comm.objst.DMap.Data.SObj)obj;
                var dobj = App.DefineFile.GetObject(sobj.DObjectId);
                if (dobj != null)
                {
                    var window = new ObjWindow(dobj.ObjFile);
                    window.ShowDialog();
                    Fill();
                    FillRes();
                }
                #endregion
            }
            else if (cmd == "editMapObj")
            {
                var key = args[0].ToString();
                var mapObj = _map.ObjDic[key];
                new PropEditWindow(mapObj).ShowDialog();
                Fill();
            }
            else if (cmd == "editMapEVDic")
            {
                #region Edit DObj
                var key = args[0].ToString();
                var obj = _map.ObjDic[key];
                var sobj = (comm.objst.DMap.Data.SObj)obj;
                var dic = new Dictionary<string, object>();
                foreach (var evKey in sobj.EVDic.Keys)
                {
                    dic.Add(evKey, sobj.EVDic[evKey].Value);
                }
                new PropEditWindow(dic).ShowDialog();
                #endregion
            }
            else if (cmd == "setGroup")
            {
                #region setGroup
                var key = args[0].ToString();
                var groupKey = args[1].ToString();
                if (_map.ObjDic.ContainsKey(key))
                {
                    var mobj = _map.ObjDic[key];
                    if (mobj is comm.objst.DMap.Data.Sprite)
                    {
                        var sprite = (comm.objst.DMap.Data.Sprite)mobj;
                        sprite.SpriteGroupKey = groupKey;
                    }
                    else if (mobj is comm.objst.DMap.Data.SObj)
                    {
                        var SObj = (comm.objst.DMap.Data.SObj)mobj;
                        SObj.DesignSpriteGroupKey = groupKey;
                    }
                    Fill();
                }
                #endregion
            }
            else if (cmd == "setAction")
            {
                #region setAction
                var key = args[0].ToString();
                var acKey = args[1].ToString();
                if (_map.ObjDic.ContainsKey(key))
                {
                    var mobj = _map.ObjDic[key]; if (mobj is comm.objst.DMap.Data.SObj)
                    {
                        var SObj = (comm.objst.DMap.Data.SObj)mobj;
                        SObj.DesignAction = acKey;
                    }
                    Fill();
                }
                #endregion
            }
            else if (cmd == "copy")
            {
                var key = args[0].ToString();
                var mapObj = _map.ObjDic[key];
                var newMapObj = comm.BinarySerializer.Deserialize<comm.objst.DMap.Data.Obj>(comm.BinarySerializer.Serialize(mapObj));
                _map.ObjDic.Add(comm.GUID.NewString(), newMapObj);
                Fill();
            }
        }
        void Log(string text)
        {
            spLog.Children.Add(new Border
            {
                Child = new TextBlock
                {
                    Width = spLog.Width,
                    Text = text,
                    TextWrapping = TextWrapping.Wrap
                },
                BorderBrush = new SolidColorBrush(Color2.White(50)),
                BorderThickness = new Thickness(0, 0, 0, 1)
            });
        }

        void SaveFile()
        {
            try
            {
                var exDic = _map.RemoveExObjDic();
                if (_externalObjDic != null)
                {
                    _externalObjDic = exDic;
                }

                if (OnSaveCallback != null)
                {
                    OnSaveCallback(exDic);
                }

                var bytes = comm.BinarySerializer.Serialize(_map);
                io.File.WriteAllBytes(_fileName, bytes);

                _map.AddExObjDic(exDic);

                MakeSign();
            }
            catch (Exception ex)
            {
                MessageBox.Show("save file:" + _fileName + " err!" + ex.Message);
            }
        }
        void OpenFile()
        {
            try
            {
                _map = comm.BinarySerializer.Deserialize<comm.objst.DMap.Data>(io.File.ReadAllBytes(_fileName));
                if (_externalObjDic != null)
                {
                    _map.AddExObjDic(_externalObjDic);
                }

                MakeSign();
                Fill();
            }
            catch (Exception ex)
            {
                MessageBox.Show("open file:" + _fileName + " err!" + ex.Message);
            }
        }
        void MakeSign()
        {
            _sign = comm.Safety.SHA1Encode(comm.BinarySerializer.Serialize(_map));
        }
        bool CheckSignChange()
        {
            return _sign != comm.Safety.SHA1Encode(comm.BinarySerializer.Serialize(_map));
        }
    }
}
